/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.oszero.deliver.admin.interceptor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.oszero.deliver.admin.model.common.CommonResult;
import com.oszero.deliver.admin.model.entity.UserInfo;
import com.oszero.deliver.admin.model.property.AuthAttributeProperty;
import com.oszero.deliver.admin.util.HttpClientUtil;
import com.oszero.deliver.admin.util.ThreadLocalUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.message.BasicNameValuePair;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;

import static com.oszero.deliver.admin.constant.CommonConstant.AUTH_HEARD_NAME;

/**
 * 用户拦截器
 *
 * @author oszero
 * @version 1.0.0
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class UserInterceptor implements HandlerInterceptor
{
    private final AuthAttributeProperty authAttributeProperty;
    @Value("${server.test-mode}")
    private boolean testMode;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
    {
        if(testMode)
        {
            ThreadLocalUtils.setUserInfo(UserInfo.builder()
                    .userId("admin").abpUserId("admin").abpTenantId("2").realName("超级管理员").departmentId("1").build());
        }
        else
        {
            // 获取URI
            String requestURI = request.getRequestURI();

            // URI检测
            // 无权限接口
            if (
                    requestURI.contains("/admin/authAny") ||
                    requestURI.contains("/open/sendMessage")
                )
                return true;

            // 获取token
            String token = request.getHeader(AUTH_HEARD_NAME);
            if (StringUtils.isBlank(token)) {
                assemblyResponse(response, JSON.toJSONString(CommonResult.fail("凭证不存在")));
                return false;
            }

            // token校验
            UserInfo userInfo = checkToken(token);
            if (userInfo == null) {
                assemblyResponse(response, JSON.toJSONString(CommonResult.fail("无效凭证")));
                return false;
            }

            // 转换
            ThreadLocalUtils.setUserInfo(userInfo);
        }
        return true;
    }

    /**
     * response组装
     */
    private static void assemblyResponse(HttpServletResponse response, String json) throws IOException {
        response.setStatus(401);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        PrintWriter out = response.getWriter();
        out.print(json);
        out.flush();
    }

    /**
     * token校验
     */
    private UserInfo checkToken(String token) {
        try {
            token = token.replace("Bearer", "").trim();
            String checkTokenUrl = authAttributeProperty.getUrl() + authAttributeProperty.getCheckToken();
            String response = HttpClientUtil.getRequest(
                    checkTokenUrl,
                    Collections.singletonList(new BasicNameValuePair("token", token))
            );

            JSONObject resJsonObject = JSONObject.parseObject(response);
            if (!resJsonObject.getBoolean("active"))
                return null;

            JSONArray authorities = resJsonObject.getJSONArray("authorities");

            //平台管理员才能登录
            if(!authorities.stream().anyMatch(item -> item.toString().equals("admin")))
                return null;

            UserInfo userInfo = UserInfo.builder()
                    .userName(resJsonObject.getString("user_name"))
                    .build();

            for (Object authority : authorities) {
                String str = authority.toString();
                if (str.startsWith("abp_user"))
                    userInfo.setAbpUserId(str.replace("abp_user_",""));
                else if (str.startsWith("abp_tenant"))
                    userInfo.setAbpTenantId(str.replace("abp_tenant_",""));
                else if (str.startsWith("tenant"))
                    userInfo.setTenantId(str.replace("tenant_",""));
                else if (str.startsWith("department"))
                    userInfo.setDepartmentId(str.replace("department_",""));
                else if (str.startsWith("user"))
                    userInfo.setUserId(str.replace("user_",""));
                else if (str.startsWith("real_name"))
                    userInfo.setRealName(str.replace("real_name_",""));
            }

            return userInfo;
        } catch (Exception e) {
            log.error("====================token校验异常: {}", e.getMessage());
            return null;
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        ThreadLocalUtils.clear();
    }
}
